package common.stack.delayStack.two;

import common.stack.delayStack.DelayedStack;

public class MyStack<E> implements DelayedStack<E> {

    class StackNode<E> {
        private E data;
        private StackNode<E> pre;

        public StackNode(E data, StackNode<E> pre) {
            this.data = data;
            this.pre = pre;
        }
    }

    public StackNode<E> tail;
    private int size;
    private int maximumDelay;
    private int delay;
    private boolean pop;

    public MyStack(int maximumDelay) {
        this.tail = null;
        this.size = 0;
        this.maximumDelay = maximumDelay;
        this.delay = maximumDelay;
        this.pop = false;
    }

    public int size() {
        return size;
    }

    public void push(E element) {
        StackNode<E> node = new StackNode<>(element, null);
        if (tail == null) {
            tail = node;
        } else {
            node.pre = tail;
            tail = node;
        }

        if (pop && delay <= 0) {
            this.pop = false;
            this.delay = this.maximumDelay;
        }
        this.delay--;
        this.size++;

    }

    public E pop() throws IllegalStateException {
        if (size == 0) {
            throw new IllegalStateException();
        }else if (delay > 0) {
            return null;
        } else {
            E data = tail.data;
            tail = tail.pre;
            size--;
            pop = true;
            return data;
        }
    }

    public E peek() throws IllegalStateException {
        if (size == 0) {
            throw new IllegalStateException();
        } else {
            return tail.data;
        }
    }

    public int getDelay() {
        return Math.max(delay, 0);
    }

    public void setMaximumDelay(int d) {
        this.maximumDelay = d;
    }

    public int getMaximumDelay() {
        return maximumDelay;
    }

    public boolean clear() {
        if (delay <= 0) {
            this.tail = null;
            this.size = 0;
            this.pop = true;
        }
        return delay <= 0;
    }

    public boolean contains(E elem) {
        StackNode<E> node = tail;
        while (node != null) {
            E data = node.data;
            if (data == null && elem == null) {
                return true;
            } else if (data != null && data.equals(elem)) {
                return true;
            } else if (elem != null && elem.equals(data)) {
                return true;
            }

            node = node.pre;
        }
        return false;
    }
}